﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.SharePoint;
using SlamCms.SharePoint.SlamProfiles.ContentItem;
using SlamCms.SharePoint.Tagging;
using System.Net;
using Slam;
using Slam.Logging;
using Slam.SharePoint;
using System.Threading;
using SlamCms.SharePoint.SlamProfiles.ContentItem.Data;
using System.Collections;
using System.Text.RegularExpressions;
using Slam.Configuration;
using SlamCms.SharePoint.Core;

namespace SlamCms.SharePoint.SlamProfiles.ContentItem.Services
{
	public static class ContentItemServices
	{
		internal static Hashtable GetContentItemFieldValues(SPListItem listItem, ContentItemProfileSection contentItemSection, ContentItemConfiguredType contentItemType, List<Field> contentItemFields, IEnumerable<ContentItemField> typeContentItemfields, List<Field> typeFields, DataService contentItemDataService, string dataSchema)
		{
			SPList parentList = listItem.ParentList;
			string siteCollection = listItem.Web.Site.ServerRelativeUrl.TrimStart('/');

			Hashtable values = listItem.GetFieldValues(contentItemFields);

			Field titleField = typeFields.Where(f => !f.Name.ToUpper().EndsWith("ID")).FirstOrDefault();
			string referenceTitle = Convert.ToString(listItem[titleField.Name]);
			if (titleField.Name.Equals("Title", StringComparison.OrdinalIgnoreCase))
			{
				referenceTitle = listItem.GetTitle();
			}
			if (values.ContainsKey("ReferenceTitle"))
			{
				values["ReferenceTitle"] = referenceTitle;
			}
			else
			{
				values.Add("ReferenceTitle", referenceTitle);
			}

			if (values.ContainsKey("Slug"))
			{
				values["Slug"] = listItem.FormatFrontEndUrl(contentItemType.SlugFormat, contentItemType);
			}
			else
			{
				values.Add("Slug", listItem.FormatFrontEndUrl(contentItemType.SlugFormat, contentItemType));
			}
			
			if (values.ContainsKey("ContentTypeID"))
			{
				values["ContentTypeID"] = ContentItemServices.GetContentTypeIdAndEnsureItemIsSlammed(contentItemType.ContentItemType, listItem);
			}
			else
			{
				values.Add("ContentTypeID", ContentItemServices.GetContentTypeIdAndEnsureItemIsSlammed(contentItemType.ContentItemType, listItem));
			}

			if (values.ContainsKey("FrontEndUrl"))
			{
				values["FrontEndUrl"] = listItem.FormatFrontEndUrl(contentItemType.FrontEndUrl, contentItemType);
			}
			else
			{
				values.Add("FrontEndUrl", listItem.FormatFrontEndUrl(contentItemType.FrontEndUrl, contentItemType));
			}

			if (!contentItemDataService.VerifyTableExists(dataSchema, "User"))
			{
				contentItemDataService.CreateUserTable(dataSchema);
			}
			int modifiedUserId = 0;
			string editorValue = Convert.ToString(listItem[SPBuiltInFieldId.Editor]);
			if (!String.IsNullOrEmpty(editorValue))
			{
				try
				{
					SPFieldLookupValue modifiedByValue = new SPFieldLookupValue(editorValue);
					var modifiedByUser = new SPFieldUserValue(listItem.Web, modifiedByValue.ToString());
					string modifiedByUserName = modifiedByUser.User.LoginName;
					if (modifiedByUserName.Contains("|"))
					{
						modifiedByUserName = modifiedByUserName.Split('|').Last();
					}
					modifiedUserId = contentItemDataService.RetrieveUserId(dataSchema, modifiedByUserName, String.IsNullOrEmpty(modifiedByUser.User.Name) ? modifiedByUserName : modifiedByUser.User.Name);
				}
				catch (Exception ex)
				{
					ILogger instance = ComponentService.GetInstance<ILogger>();
					instance.LogMessage("Exception", "Failed to get ModifiedBy User. " + ex.ToString());
				}
			}
			if (values.ContainsKey("ModifiedByUserID") && modifiedUserId > 0)
			{
				values["ModifiedByUserID"] = modifiedUserId;
			}
			else if (modifiedUserId > 0)
			{
				values.Add("ModifiedByUserID", modifiedUserId);
			}

			int createdUserId = 0;
			string authorValue = Convert.ToString(listItem[SPBuiltInFieldId.Author]);

			if (!String.IsNullOrEmpty(authorValue))
			{
				try
				{
					SPFieldLookupValue createdByValue = new SPFieldLookupValue(listItem[SPBuiltInFieldId.Author].ToString());
					var createdByUser = new SPFieldUserValue(listItem.Web, createdByValue.ToString());
					string createdByUserName = createdByUser.User.LoginName;
					if (createdByUserName.Contains("|"))
					{
						createdByUserName = createdByUserName.Split('|').Last();
					}
					createdUserId = contentItemDataService.RetrieveUserId(dataSchema, createdByUserName, String.IsNullOrEmpty(createdByUser.User.Name) ? createdByUserName : createdByUser.User.Name);
				}
				catch (Exception ex)
				{
					ILogger instance = ComponentService.GetInstance<ILogger>();
					instance.LogMessage("Exception", "Failed to get CreatedBy User. " + ex.ToString());
				}
			}

			if (values.ContainsKey("CreatedByUserID") && createdUserId > 0)
			{
				values["CreatedByUserID"] = createdUserId;
			}
			else if (createdUserId > 0)
			{
				values.Add("CreatedByUserID", createdUserId);
			}

			if (values.ContainsKey("CreatedDate"))
			{
				values["CreatedDate"] = listItem["Created"].ToString();
			}
			else
			{
				values.Add("CreatedDate", listItem["Created"].ToString());
			}

			if (values.ContainsKey("ModifiedDate"))
			{
				values["ModifiedDate"] = listItem["Modified"].ToString();
			}
			else
			{
				values.Add("ModifiedDate", listItem["Modified"].ToString());
			}

			string idKeyValue = contentItemFields[0] is SqlMappedField ? ((SqlMappedField)contentItemFields[0]).Column : contentItemFields[0].Name;
			string idValue = values[idKeyValue].ToString();
			string status = listItem.GetPublishingStatus();

			if (listItem.GetLiveVersionId() != 0)
			{
				if (status == ContentItemStatus.Live.Name)
				{
					idValue = listItem[contentItemFields[0].Name].ToString();
				}
				else
				{
					idValue = listItem.Versions.GetVersionFromID(listItem.GetLiveVersionId())[contentItemFields[0].Name].ToString();
				}
			}

			if (values.ContainsKey("Primary"))
			{
				values["Primary" + idKeyValue] = idValue;
			}
			else
			{
				values.Add("Primary" + idKeyValue, idValue);
			}

			Dictionary<string, int> statusValues = new Dictionary<string, int>();
			statusValues.Add(ContentItemStatus.New.Name, ContentItemStatus.New.Id);
			statusValues.Add(ContentItemStatus.PendingApprovalNew.Name, ContentItemStatus.PendingApprovalNew.Id);
			statusValues.Add(ContentItemStatus.Live.Name, ContentItemStatus.Live.Id);
			statusValues.Add(ContentItemStatus.Modified.Name, ContentItemStatus.Modified.Id);
			statusValues.Add(ContentItemStatus.PendingApprovalModified.Name, ContentItemStatus.PendingApprovalModified.Id);
			statusValues.Add(ContentItemStatus.Retired.Name, ContentItemStatus.Retired.Id);
			
			if (values.ContainsKey("StatusID"))
			{
				values["StatusID"] = statusValues[listItem.GetPublishingStatus()];
			}
			else
			{
				values.Add("StatusID", statusValues[listItem.GetPublishingStatus()]);
			}

			Hashtable additionalValues = listItem.GetFieldValues(typeContentItemfields.Cast<Field>().ToList());
			foreach (ContentItemField field in typeContentItemfields)
			{
				if (!values.ContainsKey(Regex.Replace(field.ContentItemName, "[\\W\\s]", "")) && values.ContainsKey(field.Column))
				{
					values.Add(field.ContentItemName, additionalValues[field.Column]);
					values.Remove(field.Column);
				}
			}

			return values;
		}

		public static SPListItem GetDummyLiveListItem(SPListItem listItem)
		{
			SPList list = listItem.ParentList;
			SPListItem liveItem = listItem;
			if (listItem.GetLiveVersionId() != 0)
			{
				SPListItemVersion liveVersion = listItem.Versions.GetVersionFromID(listItem.GetLiveVersionId());
				foreach (SPField field in liveVersion.Fields)
				{
					try
					{
						if (!field.Sealed && !field.ReadOnlyField && field.Title != "UniqueId")
						{
							liveItem[field.Id] = liveVersion[field.Title];
						}
					}
					catch
					{
						//If setting the value of any field fails, ignore it
					}
				}
			}
			return liveItem;
		}

		public static void ExecuteClearCacheUrl(string url, string uri, string authType, string username, string password, string domain)
		{
			if (!String.IsNullOrEmpty(url))
			{
				WebRequest request = WebRequest.Create(url);
				if (!String.IsNullOrEmpty(username) && !String.IsNullOrEmpty(password))
				{
					CredentialCache credentials = new CredentialCache();
					if (String.IsNullOrEmpty(domain))
					{
						credentials.Add(new Uri(uri), authType, new NetworkCredential(username, password));
					}
					else
					{
						credentials.Add(new Uri(uri), authType, new NetworkCredential(username, password, domain));
					}
					request.Credentials = credentials;
				}
				WebResponse response = request.GetResponse();
				response.Close();
			}
		}

		public static string GetContentTypeIdAndEnsureItemIsSlammed(string contentTypeName, SPListItem listItem)
		{
			string itemId = "";
			SlamCmsContext.GlobalSettings(gs =>
			{
				SPList contentTypes = gs.Lists["Content Types"];
				foreach (SPListItem item in contentTypes.Items)
				{
					if (item.Title == contentTypeName)
					{
						if (item.VerifyItemRequiresSlamUpdate())
						{
							item.SlamUpdate();
						}
						itemId = item.GetUniqueId().ToString();
						break;
					}
				}
			}, listItem.Web.Url);

			return itemId;
		}

		public static void EnsureStatusContentTypeField(SPListItem listItem, SPContentType contentType)
		{
			SPList list = listItem.ParentList;

			if (contentType.Sealed)
			{
				EnsureStatusListField(listItem);
			}
			else if (contentType.FieldLinks[ContentItemFieldIdentifier.PublishingStatusInternalName] == null)
			{
				using (SPWeb rootWeb = list.ParentWeb.Site.RootWeb)
				{
					if (!rootWeb.Fields.ContainsField(ContentItemFieldIdentifier.PublishingStatusDisplayName))
					{
						SPField newField = rootWeb.Fields.CreateNewField("Text", ContentItemFieldIdentifier.PublishingStatusDisplayName);
						newField.ShowInEditForm = false;
						newField.ShowInDisplayForm = false;
						newField.ShowInListSettings = false;
						newField.ShowInNewForm = false;
						newField.ShowInVersionHistory = false;
						rootWeb.Fields.Add(newField);
						rootWeb.AllowUnsafeUpdates = true;
						rootWeb.Update();

						Thread.Sleep(800);
					}

					SPContentType topContentType = rootWeb.ContentTypes[contentType.Name];

					if (topContentType.FieldLinks["Status"] != null)
					{	
						topContentType.FieldLinks.Delete("Status");
						try
						{
							rootWeb.AllowUnsafeUpdates = true;
							topContentType.Update(true);
						}
						catch (Exception ex)
						{
							//SharePoint has this wonderful feature that enables us to not
							//check whether a Content Type has children.  If it does not
							//the above Update will throw an exception.  If it is does, the following
							//will not work the way we want.
							topContentType.Update();
						}

						if (list.Fields.ContainsFieldWithStaticName("Status"))
						{
							SPField oldStatusField = list.Fields.GetFieldByInternalName("Status");
							oldStatusField.Delete();
						}
					}

					if (topContentType.FieldLinks[ContentItemFieldIdentifier.PublishingStatusInternalName] == null)
					{
						rootWeb.AllowUnsafeUpdates = true;
						topContentType.FieldLinks.Add(new SPFieldLink(rootWeb.Fields.GetFieldByInternalName(ContentItemFieldIdentifier.PublishingStatusInternalName)));
						SPFieldLink fieldLink = topContentType.FieldLinks[ContentItemFieldIdentifier.PublishingStatusInternalName];
						fieldLink.ShowInDisplayForm = false;
						try
						{
							rootWeb.AllowUnsafeUpdates = true;
							topContentType.Update(true);
						}
						catch (Exception ex)
						{
							//SharePoint has this wonderful feature that enables us to not
							//check whether a Content Type has children.  If it does not
							//the above Update will throw an exception.  If it is does, the following
							//will not work the way we want.
							topContentType.Update();
						}
					}
				}
			}
		}

		public static void EnsureStatusListField(SPListItem listItem)
		{
			SPList list = listItem.ParentList;

			if (!list.Fields.ContainsField(ContentItemFieldIdentifier.PublishingStatusDisplayName))
			{
				using (SPWeb rootWeb = list.ParentWeb.Site.RootWeb)
				{
					if (!rootWeb.Fields.ContainsField(ContentItemFieldIdentifier.PublishingStatusDisplayName))
					{
						SPField newField = rootWeb.Fields.CreateNewField("Text", ContentItemFieldIdentifier.PublishingStatusDisplayName);
						newField.ShowInEditForm = false;
						newField.ShowInDisplayForm = false;
						newField.ShowInListSettings = false;
						newField.ShowInNewForm = false;
						newField.ShowInVersionHistory = false;
						rootWeb.Fields.Add(newField);
						rootWeb.AllowUnsafeUpdates = true;
						rootWeb.Update();
						Thread.Sleep(800);
					}

					if (list.Fields.ContainsFieldWithStaticName("Status"))
					{
						SPField oldStatusField = list.Fields.GetFieldByInternalName("Status");
						if (oldStatusField != null)
						{
							oldStatusField.Delete();
						}
					}

					if (!list.Fields.ContainsFieldWithStaticName(ContentItemFieldIdentifier.PublishingStatusInternalName))
					{
						rootWeb.AllowUnsafeUpdates = true;
						SPField newField = rootWeb.Fields.GetFieldByInternalName(ContentItemFieldIdentifier.PublishingStatusInternalName);
						SPAddFieldOptions fieldOptions = SPAddFieldOptions.AddToAllContentTypes;
						if (!list.ContentTypesEnabled)
						{
							fieldOptions = SPAddFieldOptions.AddToDefaultContentType;
						}
						list.Fields.AddFieldAsXml(newField.SchemaXml, false, fieldOptions);
						list.Update();
					}
					rootWeb.Update();
				}
			}
		}

		public static void EnsureFrontEndUrlContentTypeField(SPListItem listItem, SPContentType contentType)
		{
			SPList list = listItem.ParentList;

			if (contentType.Sealed)
			{
				EnsureFrontEndUrlListField(listItem);
			}
			else if (contentType.FieldLinks[ContentItemFieldIdentifier.FrontEndUrlInternalName] == null && contentType.FieldLinks[ContentItemFieldIdentifier.FrontEndUrlAltInternalName] == null)
			{
				using (SPWeb rootWeb = list.ParentWeb.Site.RootWeb)
				{
					if (!rootWeb.Fields.ContainsField(ContentItemFieldIdentifier.FrontEndUrlDisplayName))
					{
						rootWeb.AllowUnsafeUpdates = true;
						rootWeb.Fields.Add(ContentItemFieldIdentifier.FrontEndUrlDisplayName, SPFieldType.Text, false);
						rootWeb.Fields[ContentItemFieldIdentifier.FrontEndUrlDisplayName].Hidden = true;
						rootWeb.AllowUnsafeUpdates = true;
						rootWeb.Update();

						Thread.Sleep(800);
					}

					SPContentType topContentType = rootWeb.ContentTypes[contentType.Name];
					if (topContentType.FieldLinks[ContentItemFieldIdentifier.FrontEndUrlInternalName] == null && topContentType.FieldLinks[ContentItemFieldIdentifier.FrontEndUrlAltInternalName] == null)
					{
						rootWeb.AllowUnsafeUpdates = true;
						topContentType.FieldLinks.Add(new SPFieldLink(rootWeb.Fields[ContentItemFieldIdentifier.FrontEndUrlDisplayName]));
						SPFieldLink fieldLink = topContentType.FieldLinks[ContentItemFieldIdentifier.FrontEndUrlInternalName];
						if (fieldLink == null)
						{
							fieldLink = topContentType.FieldLinks[ContentItemFieldIdentifier.FrontEndUrlAltInternalName];
						}
						fieldLink.Hidden = true;

						try
						{
							rootWeb.AllowUnsafeUpdates = true;
							topContentType.Update(true);
						}
						catch (Exception ex)
						{
							//SharePoint has this wonderful feature that enables us to not
							//check whether a Content Type has children.  If it does not
							//the above Update will throw an exception.  If it is does, the following
							//will not work the way we want.
							topContentType.Update();
						}
					}
				}
			}
		}

		public static void EnsureFrontEndUrlListField(SPListItem listItem)
		{
			SPList list = listItem.ParentList;

			if (!list.Fields.ContainsField(ContentItemFieldIdentifier.FrontEndUrlDisplayName))
			{
				using (SPWeb rootWeb = list.ParentWeb.Site.RootWeb)
				{
					if (!rootWeb.Fields.ContainsField(ContentItemFieldIdentifier.FrontEndUrlDisplayName))
					{
						rootWeb.AllowUnsafeUpdates = true;
						rootWeb.Fields.Add(ContentItemFieldIdentifier.FrontEndUrlDisplayName, SPFieldType.Text, false);
						rootWeb.Fields[ContentItemFieldIdentifier.FrontEndUrlDisplayName].Hidden = true;
						rootWeb.AllowUnsafeUpdates = true;
						rootWeb.Update();
						Thread.Sleep(800);
					}

					if (!list.Fields.ContainsField(ContentItemFieldIdentifier.FrontEndUrlDisplayName))
					{
						rootWeb.AllowUnsafeUpdates = true;
						SPField newField = rootWeb.Fields[ContentItemFieldIdentifier.FrontEndUrlDisplayName];
						SPAddFieldOptions fieldOptions = SPAddFieldOptions.AddToAllContentTypes;
						if (!list.ContentTypesEnabled)
						{
							fieldOptions = SPAddFieldOptions.AddToDefaultContentType;
						}
						list.Fields.AddFieldAsXml(newField.SchemaXml, false, fieldOptions);
						list.Update();

						Thread.Sleep(800);

						rootWeb.AllowUnsafeUpdates = true;
						SPField field = list.Fields[ContentItemFieldIdentifier.FrontEndUrlDisplayName];
						field.Hidden = true;
						field.Update();
					}
					rootWeb.Update();
				}
			}
		}

		public static void EnsureLiveVersionIdField(this SPListItem listItem)
		{
			if (!listItem.Fields.ContainsField(ContentItemFieldIdentifier.LiveVersionIdInternalName))
			{
				SPWeb web = listItem.Web;
				SPList parentList = web.Lists[listItem.ParentList.ID];
				SPField newField = parentList.Fields.CreateNewField("Text", ContentItemFieldIdentifier.LiveVersionIdInternalName);
				newField.Hidden = true;
				parentList.Fields.Add(newField);
				web.AllowUnsafeUpdates = true;
				parentList.Update();
			}
		}
	}
}
